﻿using System;
using System.Collections.Generic;
using System.IO;
using DimensionsHelper.Common.Table;

namespace DimensionsHelper.Common.Contracts.Table;

/// <summary>
///     表格的读取类，可以使用不同的文本分隔符，以单元格文本的形式读取文件或数据对象，
///     并且可以依据一定规则区分可能的数据表格。
/// </summary>
public interface ITableReader : IEnumerable<ITable>
{
    /// <summary>
    ///     获取当前已读取的行总数。
    /// </summary>
    int LinesCount { get; }

    /// <summary>
    ///     获取当前已读取的表格总数。
    /// </summary>
    int TablesCount { get; }

    /// <summary>
    ///     获取当前的第一个表格，可能是插入进来的。
    /// </summary>
    ITable? FirstTable { get; }

    /// <summary>
    ///     获取当前的最后一个表格，可能是插入进来的。
    /// </summary>
    ITable? LastTable { get; }

    /// <summary>
    ///     获取已读取到的第一个原始表格。
    /// </summary>
    ITable? FirstOriginalTable { get; }

    /// <summary>
    ///     获取已读取到的最后一个原始表格。
    /// </summary>
    ITable? LastOriginalTable { get; }

    /// <summary>
    ///     是否自动检测文本分隔符（自动检测并不一定可靠）。
    /// </summary>
    bool AutoDetectDelimiter { get; set; }

    /// <summary>
    ///     文件描述内容所在的行。
    /// </summary>
    ILine? FileSpecLine { get; }

    /// <summary>
    ///     读取行内容时触发的回调函数，如果此事件未配置，将使用默认方法读取，否则，将使用此回调读取。
    /// </summary>
    event ReadCellDataHandler<string> ReadCellData;

    /// <summary>
    ///     当<see cref="ITable" />调用<see cref="ITable.Finish" />时触发的事件。
    /// </summary>
    event EventHandler<TableFinishedEventArgs> TableFinished;

    /// <summary>
    ///     设置文本分隔符，只允许使用单字符。
    /// </summary>
    /// <param name="delimiter"></param>
    void SetDelimiter(char delimiter);

    /// <summary>
    ///     读取所有行，如果<see cref="ReadCellData" />已配置，使用回调读取，否则，使用默认方法读取。
    /// </summary>
    void ReadAllLines();

    /// <summary>
    ///     使用指定的表格识别器构建表格。
    /// </summary>
    /// <param name="recognizer">指定表格识别器</param>
    void BuildTables(ITableRecognizer recognizer);

    /// <summary>
    ///     查找标题是指定文本的表格。
    /// </summary>
    /// <param name="title">表格标题</param>
    /// <remarks>传入的表格标题需要带有标题标识符</remarks>
    ITable? FindTable(string title);

    /// <summary>
    ///     获取所有同一个标题的表格
    /// </summary>
    /// <param name="title">表格标题</param>
    /// <remarks>传入的表格标题需要带有标题标识符</remarks>
    ITable[] FindTables(string title);

    /// <summary>
    ///     将指定表格读取器读取到的表格插入到指定位置。
    /// </summary>
    /// <param name="reader">已读取的表格读取器</param>
    /// <param name="rowIndex">表格插入的行索引，0开始，此索引一直是原始文本中的索引，不考虑已插入的行数。</param>
    void InsertTablesAt(ITableReader reader, int rowIndex);

    /// <summary>
    ///     将指定文件中的表格插入到已有的表格列表中的指定位置。
    /// </summary>
    /// <param name="recognizer">指定表格识别器</param>
    /// <param name="stream">插入的文件流，注意，此参数值不负责设置编码</param>
    /// <param name="rowIndex">表格插入的行索引，0开始，此索引一直是原始文本中的索引，不考虑已插入的行数。</param>
    void InsertTablesAt(ITableRecognizer recognizer, StreamReader stream, int rowIndex);

    /// <summary>
    ///     将指定文件流中的表格插入到已有的表格列表中的指定位置。
    /// </summary>
    /// <param name="recognizer">指定表格识别器</param>
    /// <param name="fileStream">插入的文件流，方法应当自动检测文件编码</param>
    /// <param name="index">表格插入的索引，0开始。如果给定索引为0，插入到开头；如果大于当前表格数量，插入到末尾。如果是负数，插入到末尾。</param>
    void InsertTablesAt(ITableRecognizer recognizer, FileStream fileStream, int index);

    /// <summary>
    ///     将指定表格读取器已读取的表格插入到当前表格列表的指定表格前。
    ///     如果给定的表格名不存在，将插入到最后。
    /// </summary>
    /// <param name="reader">已读取的表格读取器</param>
    /// <param name="tableName">指定的表格名，此名称需要和文本文件中的完全相同</param>
    void InsertTablesBefore(ITableReader reader, string tableName);

    /// <summary>
    ///     将指定文件流中的表格插入到给定表格名的表格前。
    ///     如果给定表格不存在，将插入到最后。
    /// </summary>
    /// <param name="recognizer">指定表格识别器</param>
    /// <param name="stream">插入的文件流</param>
    /// <param name="tableName">指定的表格名，此名称需要和文本文件中的完全相同</param>
    void InsertTablesBefore(ITableRecognizer recognizer, StreamReader stream, string tableName);

    /// <summary>
    ///     将指定文件流中的表格插入到给定表格名的表格前。
    ///     如果给定的表格不存在，将插入到最后。
    /// </summary>
    /// <param name="recognizer">指定表格识别器</param>
    /// <param name="fileStream">插入的文件流，方法应当自动检测文件编码</param>
    /// <param name="tableName">指定的表格名，此名称需要和文本文件中的完全相同</param>
    void InsertTablesBefore(ITableRecognizer recognizer, FileStream fileStream, string tableName);

    /// <summary>
    ///     使用传入的表格替换读取到的同名表格
    /// </summary>
    /// <param name="tables">待替换的表格</param>
    void ReplaceTables(IEnumerable<ITable> tables);

    /// <summary>
    ///     读取指定流。
    /// </summary>
    /// <param name="streamReader"></param>
    void ReadStream(StreamReader streamReader);

    /// <summary>
    ///     读取指定文本流。
    /// </summary>
    /// <param name="fileStream"></param>
    void ReadStream(FileStream fileStream);

    /// <summary>
    ///     释放当前的文件流引用，如果使用的是外部文件流，此方法不调用<see cref="IDisposable.Dispose" />方法。
    /// </summary>
    void FinishStream();

    /// <summary>
    ///     清空已读取的内容。
    /// </summary>
    void Clear();
}